"""
性能监控仪表板 - 实时展示系统性能指标和趋势分析
"""
import asyncio
import json
import time
from datetime import datetime, timedelta
from typing import Dict, Any, List, Optional
from dataclasses import dataclass, asdict
import aiohttp
import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
from jinja2 import Template
import pandas as pd
from utils.logger import Logger

logger = Logger.get_logger("performance_dashboard")


@dataclass
class MetricPoint:
    """指标数据点"""
    timestamp: datetime
    value: float
    label: str
    
    def to_dict(self) -> Dict[str, Any]:
        return {
            "timestamp": self.timestamp.isoformat(),
            "value": self.value,
            "label": self.label
        }


@dataclass
class SystemMetrics:
    """系统指标"""
    cpu_usage: float
    memory_usage: float
    disk_usage: float
    network_io: float
    active_connections: int
    queue_size: int
    error_rate: float
    response_time_p95: float
    throughput_rps: float
    
    def to_dict(self) -> Dict[str, Any]:
        return asdict(self)


class MetricsCollector:
    """指标收集器"""
    
    def __init__(self, prometheus_url: str = "http://localhost:9090"):
        self.prometheus_url = prometheus_url
        self.metrics_history: Dict[str, List[MetricPoint]] = {}
        self.max_history_points = 1000  # 最多保留1000个数据点
        
    async def collect_metrics(self) -> SystemMetrics:
        """收集系统指标"""
        try:
            # 这里应该调用真实的监控API
            # 现在使用模拟数据
            metrics = SystemMetrics(
                cpu_usage=self._get_cpu_usage(),
                memory_usage=self._get_memory_usage(),
                disk_usage=self._get_disk_usage(),
                network_io=self._get_network_io(),
                active_connections=self._get_active_connections(),
                queue_size=self._get_queue_size(),
                error_rate=self._get_error_rate(),
                response_time_p95=self._get_response_time_p95(),
                throughput_rps=self._get_throughput_rps()
            )
            
            # 存储历史数据
            self._store_metrics(metrics)
            
            return metrics
            
        except Exception as e:
            logger.error(f"指标收集失败: {str(e)}")
            # 返回默认值
            return SystemMetrics(
                cpu_usage=0.0, memory_usage=0.0, disk_usage=0.0,
                network_io=0.0, active_connections=0, queue_size=0,
                error_rate=0.0, response_time_p95=0.0, throughput_rps=0.0
            )
    
    def _get_cpu_usage(self) -> float:
        """获取CPU使用率"""
        # 这里应该调用真实的系统API
        import random
        return random.uniform(20.0, 80.0)
    
    def _get_memory_usage(self) -> float:
        """获取内存使用率"""
        import random
        return random.uniform(40.0, 90.0)
    
    def _get_disk_usage(self) -> float:
        """获取磁盘使用率"""
        import random
        return random.uniform(30.0, 70.0)
    
    def _get_network_io(self) -> float:
        """获取网络IO"""
        import random
        return random.uniform(100.0, 1000.0)
    
    def _get_active_connections(self) -> int:
        """获取活跃连接数"""
        import random
        return random.randint(50, 500)
    
    def _get_queue_size(self) -> int:
        """获取队列大小"""
        import random
        return random.randint(0, 100)
    
    def _get_error_rate(self) -> float:
        """获取错误率"""
        import random
        return random.uniform(0.0, 5.0)
    
    def _get_response_time_p95(self) -> float:
        """获取P95响应时间"""
        import random
        return random.uniform(50.0, 500.0)
    
    def _get_throughput_rps(self) -> float:
        """获取吞吐量"""
        import random
        return random.uniform(100.0, 1000.0)
    
    def _store_metrics(self, metrics: SystemMetrics):
        """存储指标历史"""
        timestamp = datetime.utcnow()
        
        # 存储每个指标
        for metric_name, value in metrics.to_dict().items():
            if metric_name not in self.metrics_history:
                self.metrics_history[metric_name] = []
            
            metric_point = MetricPoint(timestamp, value, metric_name)
            self.metrics_history[metric_name].append(metric_point)
            
            # 限制历史数据点数量
            if len(self.metrics_history[metric_name]) > self.max_history_points:
                self.metrics_history[metric_name].pop(0)


class PerformanceDashboard:
    """性能监控仪表板"""
    
    def __init__(self, update_interval: int = 5):
        self.update_interval = update_interval
        self.collector = MetricsCollector()
        self.is_running = False
        self.dashboard_html = None
        
    def generate_realtime_dashboard(self) -> str:
        """生成实时监控仪表板"""
        try:
            # 收集当前指标
            metrics = asyncio.run(self.collector.collect_metrics())
            
            # 创建仪表板
            fig = make_subplots(
                rows=3, cols=3,
                subplot_titles=[
                    'CPU使用率 (%)', '内存使用率 (%)', '磁盘使用率 (%)',
                    '网络IO (MB/s)', '活跃连接数', '队列大小',
                    '错误率 (%)', 'P95响应时间 (ms)', '吞吐量 (RPS)'
                ],
                specs=[
                    [{"type": "indicator"}, {"type": "indicator"}, {"type": "indicator"}],
                    [{"type": "indicator"}, {"type": "indicator"}, {"type": "indicator"}],
                    [{"type": "indicator"}, {"type": "indicator"}, {"type": "indicator"}]
                ]
            )
            
            # 添加指标指示器
            indicators = [
                (1, 1, 'CPU使用率', metrics.cpu_usage, 0, 100, 'red' if metrics.cpu_usage > 80 else 'green'),
                (1, 2, '内存使用率', metrics.memory_usage, 0, 100, 'red' if metrics.memory_usage > 85 else 'green'),
                (1, 3, '磁盘使用率', metrics.disk_usage, 0, 100, 'red' if metrics.disk_usage > 90 else 'green'),
                (2, 1, '网络IO', metrics.network_io, 0, 2000, 'blue'),
                (2, 2, '活跃连接数', metrics.active_connections, 0, 1000, 'purple'),
                (2, 3, '队列大小', metrics.queue_size, 0, 200, 'orange'),
                (3, 1, '错误率', metrics.error_rate, 0, 10, 'red' if metrics.error_rate > 5 else 'green'),
                (3, 2, 'P95响应时间', metrics.response_time_p95, 0, 1000, 'red' if metrics.response_time_p95 > 500 else 'green'),
                (3, 3, '吞吐量', metrics.throughput_rps, 0, 2000, 'green')
            ]
            
            for row, col, title, value, min_val, max_val, color in indicators:
                fig.add_trace(
                    go.Indicator(
                        mode="gauge+number+delta",
                        value=value,
                        domain={'x': [0, 1], 'y': [0, 1]},
                        title={'text': title},
                        gauge={'axis': {'range': [min_val, max_val]},
                               'bar': {'color': color}}
                    ),
                    row=row, col=col
                )
            
            fig.update_layout(
                title=f"MAESS 系统性能监控仪表板 - {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}",
                height=800,
                showlegend=False
            )
            
            return fig.to_html(include_plotlyjs='cdn')
            
        except Exception as e:
            logger.error(f"生成仪表板失败: {str(e)}")
            return f"<h3>仪表板生成失败: {str(e)}</h3>"
    
    def generate_trends_chart(self, metric_name: str, time_range_hours: int = 1) -> str:
        """生成趋势图表"""
        try:
            if metric_name not in self.collector.metrics_history:
                return f"<h3>没有 {metric_name} 的历史数据</h3>"
            
            history = self.collector.metrics_history[metric_name]
            
            # 过滤时间范围
            cutoff_time = datetime.utcnow() - timedelta(hours=time_range_hours)
            filtered_history = [point for point in history if point.timestamp > cutoff_time]
            
            if not filtered_history:
                return f"<h3>最近 {time_range_hours} 小时内没有数据</h3>"
            
            # 创建数据框
            df = pd.DataFrame([
                {
                    'timestamp': point.timestamp,
                    'value': point.value,
                    'label': point.label
                }
                for point in filtered_history
            ])
            
            # 创建趋势图
            fig = go.Figure()
            
            fig.add_trace(go.Scatter(
                x=df['timestamp'],
                y=df['value'],
                mode='lines+markers',
                name=metric_name,
                line=dict(color='blue', width=2),
                marker=dict(size=4)
            ))
            
            fig.update_layout(
                title=f"{metric_name} 趋势图 - 最近 {time_range_hours} 小时",
                xaxis_title="时间",
                yaxis_title="值",
                height=400,
                hovermode='x unified'
            )
            
            return fig.to_html(include_plotlyjs='cdn')
            
        except Exception as e:
            logger.error(f"生成趋势图失败: {str(e)}")
            return f"<h3>趋势图生成失败: {str(e)}</h3>"
    
    def generate_comparison_chart(self, metric_names: List[str]) -> str:
        """生成对比图表"""
        try:
            # 获取最新的指标值
            latest_metrics = asyncio.run(self.collector.collect_metrics())
            
            # 创建对比数据
            values = []
            labels = []
            
            for metric_name in metric_names:
                if hasattr(latest_metrics, metric_name):
                    values.append(getattr(latest_metrics, metric_name))
                    labels.append(metric_name.replace('_', ' ').title())
            
            if not values:
                return "<h3>没有有效的对比指标</h3>"
            
            # 创建对比图
            fig = go.Figure()
            
            fig.add_trace(go.Bar(
                x=labels,
                y=values,
                text=[f'{v:.2f}' for v in values],
                textposition='auto',
                marker_color=['red' if v > 70 else 'orange' if v > 50 else 'green' for v in values]
            ))
            
            fig.update_layout(
                title="性能指标对比",
                xaxis_title="指标",
                yaxis_title="值",
                height=400
            )
            
            return fig.to_html(include_plotlyjs='cdn')
            
        except Exception as e:
            logger.error(f"生成对比图失败: {str(e)}")
            return f"<h3>对比图生成失败: {str(e)}</h3>"
    
    def generate_html_dashboard(self) -> str:
        """生成完整的HTML仪表板"""
        try:
            # 生成各个组件
            realtime_dashboard = self.generate_realtime_dashboard()
            
            # 生成趋势图
            cpu_trends = self.generate_trends_chart('cpu_usage', 1)
            memory_trends = self.generate_trends_chart('memory_usage', 1)
            response_time_trends = self.generate_trends_chart('response_time_p95', 1)
            throughput_trends = self.generate_trends_chart('throughput_rps', 1)
            
            # 生成对比图
            comparison_chart = self.generate_comparison_chart([
                'cpu_usage', 'memory_usage', 'disk_usage', 'error_rate'
            ])
            
            # HTML模板
            html_template = """
            <!DOCTYPE html>
            <html lang="zh-CN">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>MAESS 性能监控仪表板</title>
                <style>
                    body {
                        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                        margin: 0;
                        padding: 20px;
                        background-color: #f5f5f5;
                    }
                    .header {
                        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                        color: white;
                        padding: 20px;
                        border-radius: 10px;
                        margin-bottom: 20px;
                        text-align: center;
                    }
                    .dashboard-container {
                        background: white;
                        border-radius: 10px;
                        padding: 20px;
                        margin-bottom: 20px;
                        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
                    }
                    .trends-container {
                        display: grid;
                        grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
                        gap: 20px;
                        margin-bottom: 20px;
                    }
                    .trend-chart {
                        background: white;
                        border-radius: 10px;
                        padding: 15px;
                        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
                    }
                    .comparison-container {
                        background: white;
                        border-radius: 10px;
                        padding: 20px;
                        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
                    }
                    .refresh-info {
                        text-align: center;
                        color: #666;
                        margin-top: 20px;
                        font-size: 14px;
                    }
                    .status-indicator {
                        display: inline-block;
                        width: 12px;
                        height: 12px;
                        border-radius: 50%;
                        margin-right: 8px;
                    }
                    .status-good { background-color: #28a745; }
                    .status-warning { background-color: #ffc107; }
                    .status-bad { background-color: #dc3545; }
                    .metrics-summary {
                        display: grid;
                        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
                        gap: 15px;
                        margin: 20px 0;
                    }
                    .metric-card {
                        background: #f8f9fa;
                        border-radius: 8px;
                        padding: 15px;
                        text-align: center;
                        border-left: 4px solid #007bff;
                    }
                    .metric-value {
                        font-size: 24px;
                        font-weight: bold;
                        color: #333;
                    }
                    .metric-label {
                        font-size: 14px;
                        color: #666;
                        margin-top: 5px;
                    }
                </style>
            </head>
            <body>
                <div class="header">
                    <h1>🚀 MAESS 智能体系统性能监控仪表板</h1>
                    <p>实时监控多智能体系统的性能指标和运行状态</p>
                </div>
                
                <div class="dashboard-container">
                    <h2>📊 实时性能指标</h2>
                    {{ realtime_dashboard }}
                </div>
                
                <div class="trends-container">
                    <div class="trend-chart">
                        <h3>💻 CPU 使用率趋势</h3>
                        {{ cpu_trends }}
                    </div>
                    <div class="trend-chart">
                        <h3>🧠 内存使用率趋势</h3>
                        {{ memory_trends }}
                    </div>
                    <div class="trend-chart">
                        <h3>⏱️ P95 响应时间趋势</h3>
                        {{ response_time_trends }}
                    </div>
                    <div class="trend-chart">
                        <h3>📈 吞吐量趋势</h3>
                        {{ throughput_trends }}
                    </div>
                </div>
                
                <div class="comparison-container">
                    <h3>📋 性能指标对比</h3>
                    {{ comparison_chart }}
                </div>
                
                <div class="refresh-info">
                    <p>⏰ 数据每 {{ update_interval }} 秒自动更新 | 最后更新: {{ current_time }}</p>
                </div>
            </body>
            </html>
            """
            
            template = Template(html_template)
            return template.render(
                realtime_dashboard=realtime_dashboard,
                cpu_trends=cpu_trends,
                memory_trends=memory_trends,
                response_time_trends=response_time_trends,
                throughput_trends=throughput_trends,
                comparison_chart=comparison_chart,
                update_interval=self.update_interval,
                current_time=datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
            )
            
        except Exception as e:
            logger.error(f"生成HTML仪表板失败: {str(e)}")
            return f"<h3>HTML仪表板生成失败: {str(e)}</h3>"
    
    async def start_monitoring(self):
        """开始监控"""
        self.is_running = True
        logger.info("性能监控仪表板启动")
        
        while self.is_running:
            try:
                # 收集指标
                await self.collector.collect_metrics()
                
                # 生成HTML仪表板
                self.dashboard_html = self.generate_html_dashboard()
                
                # 保存到文件
                with open('performance_dashboard.html', 'w', encoding='utf-8') as f:
                    f.write(self.dashboard_html)
                
                logger.info("仪表板已更新")
                
            except Exception as e:
                logger.error(f"监控循环错误: {str(e)}")
            
            # 等待下一次更新
            await asyncio.sleep(self.update_interval)
    
    def stop_monitoring(self):
        """停止监控"""
        self.is_running = False
        logger.info("性能监控仪表板停止")
    
    def get_dashboard_url(self) -> str:
        """获取仪表板URL"""
        return "http://localhost:8080/performance_dashboard.html"


# 使用示例
async def run_performance_dashboard():
    """运行性能监控仪表板"""
    
    dashboard = PerformanceDashboard(update_interval=10)  # 10秒更新一次
    
    try:
        # 启动监控
        await dashboard.start_monitoring()
        
    except KeyboardInterrupt:
        logger.info("用户中断，停止监控")
        dashboard.stop_monitoring()
    
    except Exception as e:
        logger.error(f"仪表板运行错误: {str(e)}")
        dashboard.stop_monitoring()


if __name__ == "__main__":
    asyncio.run(run_performance_dashboard())